package com.sky.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import com.sky.entity.*;
import com.sky.listener.DishImportListener;
import com.sky.listener.DishImport;
import com.sky.mapper.CategoryMapper;
import com.sky.mapper.ReportMapper;
import com.sky.service.ReportService;
import com.sky.service.WorkspaceService;
import com.sky.vo.*;
import lombok.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;

@Service
@Slf4j
@RequiredArgsConstructor
public class ReportServiceImpl implements ReportService {
    private final ReportMapper reportMapper;
    private final WorkspaceService workspaceService;
    private final CategoryMapper categoryMapper;
    private final StringRedisTemplate redisTemplate;

    /**
     * 营业额数据统计
     *
     * @param begin
     * @param end
     * @return
     */
    @Override
    public TurnoverReportVO turnoverStatistics(LocalDate begin, LocalDate end) {
        log.info("营业额数据统计开始时间:{}", begin);
        log.info("营业额数据统计结束时间:{}", end);
        //营业额集合
        ArrayList<Double> turnoverList = new ArrayList<>();
        //获取日期列表
        ArrayList<LocalDate> dateList = new ArrayList<>();
        dateList.add(begin);
        //获取begin和end之间的所有日期
        while (!begin.equals(end)) {
            //begin+1 获取后天的数据
            begin = begin.plusDays(1);
            //添加至集合中
            dateList.add(begin);
        }
        //获取日期列表字符串
        String dateListStr = StringUtils.join(dateList, ",");

        //获取每日的营业额列表
        for (LocalDate date : dateList) {
            TurnoverReport turnoverReport = reportMapper.turnoverReport(date);
            if (turnoverReport != null) {
                //获取营业额
                Double turnover = turnoverReport.getTurnover();
                if (turnover == null) {
                    //如果为空，则添加0.00至营业额集合中
                    turnoverList.add(0.00);
                }
                //添加至营业额集合中
                turnoverList.add(turnover);
            } else {
                //如果为空，则添加0.00至营业额集合中
                turnoverList.add(0.00);
            }

        }
        //获取营业额字符串
        String turnoverListStr = StringUtils.join(turnoverList, ",");
        //封装Vo对象
        return TurnoverReportVO.builder()
                .dateList(dateListStr).turnoverList(turnoverListStr)
                .build();
    }

    /**
     * 用户数据统计
     *
     * @param begin
     * @param end
     * @return
     */
    @Override
    public UserReportVO userStatistics(LocalDate begin, LocalDate end) {
        log.info("用户数据统计开始时间:{}", begin);
        log.info("用户数据统计结束时间:{}", end);
        ArrayList<Integer> insertCountList = new ArrayList<>();
        ArrayList<Integer> countList = new ArrayList<>();
        //获取日期列表
        ArrayList<LocalDate> dateList = new ArrayList<>();
        dateList.add(begin);
        //获取begin和end之间的所有日期
        while (!begin.equals(end)) {
            //begin+1 获取后天的数据
            begin = begin.plusDays(1);
            //添加至集合中
            dateList.add(begin);
        }
        //获取日期列表字符串
        String dateListStr = StringUtils.join(dateList, ",");
        for (LocalDate date : dateList) {

//            Integer insertCount = reportMapper.countByMap(newMap);

            Integer insertCount = reportMapper.countNewByMap(date);
            insertCountList.add(insertCount);
            //获取总用户列表

//            Integer totalCount = reportMapper.countByMap(countMap);
            Integer totalCount = reportMapper.countTotalByMap(date);
            countList.add(totalCount);
        }
        //获取新增用户数字符串
        String insertCountListStr = StringUtils.join(insertCountList, ",");
        //获取总用户数字符串
        String countListStr = StringUtils.join(countList, ",");
        return UserReportVO.builder().dateList(dateListStr)
                .newUserList(insertCountListStr)
                .totalUserList(countListStr).build();
    }

    /**
     * 订单数据统计
     *
     * @param begin
     * @param end
     * @return
     */
    @Override
    public OrderReportVO getOrderStatistics(LocalDate begin, LocalDate end) {
        log.info("订单数据统计开始时间:{}", begin);
        log.info("订单数据统计结束时间:{}", end);
        //创建订单数集合
        ArrayList<Integer> orderCountList = new ArrayList<>();
        //创建有效订单数集合
        ArrayList<Integer> validOrderCountList = new ArrayList<>();
        //创建日期集合
        ArrayList<LocalDate> dateList = new ArrayList<>();
        dateList.add(begin);
        //获取日期列表
        while (!begin.equals(end)) {
            begin = begin.plusDays(1);
            dateList.add(begin);
        }
        for (LocalDate date : dateList) {
            //获取有效订单数量
            OrderReport orderReport = reportMapper.orderRepotrt(date);
            if (orderReport != null) {
                Integer validOrderCount = orderReport.getValidOrderCount();
                if (validOrderCount == null) {
                    validOrderCount = 0;
                }
                validOrderCountList.add(validOrderCount);

                Integer totalOrderCount = orderReport.getTotalOrderCount();
                if (totalOrderCount == null) {
                    totalOrderCount = 0;
                }
                orderCountList.add(totalOrderCount);
            } else {
                validOrderCountList.add(0);
                orderCountList.add(0);
            }

        }

        int validCount = reportMapper.validOrderCount();
        //获取订单总数
        int orderCount = reportMapper.totalOrderCount();
        //获取订单数字符串
        String orderCountListStr = StringUtils.join(orderCountList, ",");
        //获取有效订单数字符串
        String validOrderCountListStr = StringUtils.join(validOrderCountList, ",");
        //获取日期列表字符串
        String dateListStr = StringUtils.join(dateList, ",");
        //计算订单完成率
        double orderCompletionRate = (validCount * 1.0) / orderCount;
        //返回VO数据
        return OrderReportVO.builder()
                .orderCompletionRate(orderCompletionRate)
                .totalOrderCount(orderCount)
                .validOrderCount(validCount)
                .dateList(dateListStr)
                .orderCountList(orderCountListStr)
                .validOrderCountList(validOrderCountListStr).build();
    }

    /**
     * 销量排名统计
     *
     * @param begin
     * @param end
     * @return
     */
    @Override
    public SalesTop10ReportVO getSalesTop10(LocalDate begin, LocalDate end) {

        String key = "dish_top_report" + ":" + begin + ":" + end;
        ZSetOperations<String, String> redisZset = redisTemplate.opsForZSet();
        log.info("销量排名统计开始时间:{}", begin);
        log.info("销量排名统计结束时间:{}", end);
        //创建商品名字集合
        ArrayList<String> nameList = new ArrayList<>();
        //创建销量集合
        ArrayList<Integer> salesList = new ArrayList<>();
        //查询缓存
        Set<ZSetOperations.TypedTuple<String>> typedTuples = redisZset.reverseRangeWithScores(key, 0, -1);
        if (CollUtil.isNotEmpty(typedTuples)) {
            //缓存存在，直接返回
            for (ZSetOperations.TypedTuple<String> typedTuple : typedTuples) {
                //获取商品名字
                String name = typedTuple.getValue();
                nameList.add(name);
                //获取商品销量
                Integer number = typedTuple.getScore().intValue();
                salesList.add(number);
            }
            //获取商品名字字符串
            String nameListStr = StringUtils.join(nameList, ",");
            //获取销量字符串
            String salesListStr = StringUtils.join(salesList, ",");
            return SalesTop10ReportVO.builder()
                    .nameList(nameListStr)
                    .numberList(salesListStr)
                    .build();
        }

        List<TopReport> topReportList = reportMapper.selectList(begin, end);
        log.info("销量排名统计查询结果:{}", topReportList);
        for (TopReport topReport : topReportList) {
            //获取商品名字
            nameList.add(topReport.getName());
            //获取商品销量
            salesList.add(topReport.getNumber());
            //添加缓存
            redisZset.add(key, topReport.getName(), topReport.getNumber().doubleValue());
        }
        //获取商品名字字符串
        String nameListStr = StringUtils.join(nameList, ",");
        //获取销量字符串
        String salesListStr = StringUtils.join(salesList, ",");
        return SalesTop10ReportVO.builder()
                .nameList(nameListStr)
                .numberList(salesListStr)
                .build();
    }

    /**
     * 导出报表
     *
     * @param response
     */
    @Override
    public void export(HttpServletResponse response) {
        //创建BusinessDataVO集合
        ArrayList<BusinessDataVO> list = new ArrayList<>();
        LocalDate begin = LocalDate.now().minusDays(30);
        LocalDate end = LocalDate.now().minusDays(1);
        //获取报表数据
        //查询概览运营数据，提供给Excel模板文件
        BusinessDataVO businessData = workspaceService.getBusinessData(LocalDateTime.of(begin, LocalTime.MIN), LocalDateTime.of(end, LocalTime.MAX));
        log.info("businessData:{}", businessData);

        //获取Excel文件
        ClassPathResource pathResource = new ClassPathResource("template/运营数据报表模板.xlsx");
        InputStream inputStream = null;
        ServletOutputStream out = null;
        ExcelWriter excelWriter = null;
        try {
            HashMap<String, String> map = new HashMap<>();
            map.put("title", begin + "至" + end);
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            out = response.getOutputStream();
            inputStream = pathResource.getInputStream();
            excelWriter = EasyExcel.write(out).withTemplate(inputStream).build();
            WriteSheet sheet = EasyExcel.writerSheet().build();
            //填充数据
            excelWriter.fill(businessData, sheet);
            excelWriter.fill(map, sheet);
            //填充列表数据
            for (int i = 0; i < 30; i++) {
                LocalDate date = begin.plusDays(i);
                businessData = workspaceService.getBusinessData(LocalDateTime.of(date, LocalTime.MIN), LocalDateTime.of(date, LocalTime.MAX));
                businessData.setDate(LocalDateTimeUtil.format(date, "yyyy-MM-dd"));
                list.add(businessData);
            }
            //开启自动换行,自动换行表示每次写入一条list数据是都会重新生成一行空行,此选项默认是关闭的,需要提前设置为true
            FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
            //列表
            excelWriter.fill(list, fillConfig, sheet);
            //对象
            excelWriter.fill(list, sheet);
            excelWriter.finish();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                excelWriter.close();
                out.flush();
                out.close();
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }



    /**
     * 文件导入
     *
     * @param file
     */
    @Override
    public void importData(MultipartFile file) {
         InputStream inputStream = null;

        try {
            inputStream = file.getInputStream();
            EasyExcel.read(file.getInputStream(), DishImport.class, new DishImportListener(reportMapper,categoryMapper)).headRowNumber(3)/*从第四行开始读*/.sheet().doRead();

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }


    }
}
